
package andre.grids.filesystem.server.directorymanagement;

import andre.grids.db.*;
import andre.grids.db.dataclasses.*;
import andre.grids.network.*;
import andre.grids.filesystem.server.configuration.*;
import andre.grids.util.log.*;
import java.net.ConnectException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Iterator;

/**
 *
 * @author andre
 */
public class DirectoryManagerImpl implements IDirectoryManager {

    public void createEntryFor(String path, String remoteMaster) {        
        DbDirectory dbDir = new DbDirectory();
        dbDir.setDirName(andre.grids.util.PathUtils.win32PathToUnix(path));
        
        /* caso o diretorio ja exista, deve apenas trocar o nome do server que o controla */
        DbDirectoryQueries dirQuery = new DbDirectoryQueries();
        DbDirectory storedDir = dirQuery.getDirByName(path);        
        
        if (storedDir != null)
            dbDir = storedDir;
        
        DbPeerQueries query = new DbPeerQueries();
        dbDir.setDirOwner(query.getPeerByName(remoteMaster));
        Database db = Database.getGridFsDb();
        db.storeObjectTree(dbDir);
    }

    public void createLogEntryFor(String path) {
        System.out.println("LEMBRAR DE IMPLEMENTAR O SISTEMA DE LOG DAS MODIFICAÇÕES NO BANCO." + "Crinado o diretório: " + path);
    }

    public Remote getDirectoryOperationsFor(String master) {
        try {
            return mastersTable.getObjectsFor(master).getDirectory();
        }
        catch(RemoteException e) {
            andre.grids.util.log.Log.logException(e, this);
            return null;
        }
    }

    public String getMasterOf(String path, boolean localOnly) {
        DbDirectory dbDir = null;
        DbDirectoryQueries query = new DbDirectoryQueries();
        dbDir = query.getDirByName(path);
        if (dbDir == null && !localOnly) // caso não possua no banco o diretório pode existir em um dos outros masters, portanto deve perguntar se a busca for remota (em largura)
        {
            Enumeration<PeerObjects> objs;
            objs = mastersTable.getAllRemoteObjects();
            
            String master = null;
            while(objs.hasMoreElements())
            {
                try {
                    master = objs.nextElement().getDirectory().getDirectoryMaster(path);
                }
                catch(RemoteException e) {
                    continue;
                }
                catch(Exception e) {
                    Log.logNormalOperation(Log.OP_TYPE_QUERY, "Erro de conexão: " + e.getMessage(),this);
                }                
                if (master != null)
                    break;
            }
            
            if (master  == null) // se master é null, então ninguém na rede conhece o diretório solicitado
                return null;
            else
            {
                DbDirectory dir = new DbDirectory();
                dir.setDirName(path);
                DbPeer peer = new DbPeer();
                peer.setPeerName(master);
                peer.setDirectoryMaster(true);
                dir.setDirOwner(peer);
                Database.getGridFsDb().storeObjectTree(dir);
                if (!mastersTable.containsPeer(peer.getPeerName()))
                    mastersTable.addPeer(master);
                return master;
            }
        }
        else
            if (dbDir == null)
                return null;
            return dbDir.getDirOwner().getPeerName();
    }

    public boolean isMasterFor(String path) {
        DbPeer localPeer = null;
        DbPeerQueries query = new DbPeerQueries();
        localPeer = query.getPeerByName(ConfigurationManager.getBaseConfigInstance().getValue(ServerConfigurationProps.SERVER_HOST_NAME));
        DbDirectory dbDir = null;
        DbDirectoryQueries dquery  = new DbDirectoryQueries();
        dbDir = dquery.getDirByName(path,1); // retorna o diretório e o ativa - ativação significa buscar os dados que estão armazenados no db4o, ver referência do DB4O.
        
        if (dbDir == null)
            return false;
        
        return dbDir.getDirOwner().getPeerName().equals(localPeer.getPeerName());
    }

    public void notifyMasters(String path) {
        Enumeration<PeerObjects> objs = mastersTable.getAllRemoteObjects();
        while(objs.hasMoreElements())
        {
            PeerObjects obj;
            obj = objs.nextElement();
            try
            {
                System.err.println("chamando metodo setDirectoryMaster para: " + obj.getHost());
                System.err.println("objeto: " + obj.getDirectory().toString());
                obj.getDirectory().setDirectoryMaster(path, ConfigurationManager.getBaseConfigInstance().getValue(ServerConfigurationProps.SERVER_HOST_NAME));
            }
            catch(Exception e)
            {
                andre.grids.util.log.Log.logException(e, this);
            }
        }
    }  

    public boolean notifySuccessFor(String path, Remote dirMaster) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean requestMasterFor(String path, Remote dirMaster) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    private MasterPeerTable mastersTable;

    public MasterPeerTable getMastersTable() {
        return mastersTable;
    }

    public void setMastersTable(MasterPeerTable mastersTable) {
        this.mastersTable = mastersTable;
    }
    
    public DirectoryManagerImpl()
    {
        DirectoryOperationsConfiguration.configure(this);
    }

    public void notifyMastersDirDeletion(String path) {
        Enumeration<PeerObjects> objs = mastersTable.getAllRemoteObjects();
        while(objs.hasMoreElements())
        {
            PeerObjects obj;
            obj = objs.nextElement();
            try
            {
                System.err.println("chamando metodo setDirectoryMaster para: " + obj.getHost());
                System.err.println("objeto: " + obj.getDirectory().toString());
                obj.getDirectory().deleteDirectory(path);
            }
            catch(Exception e)
            {
                andre.grids.util.log.Log.logException(e, this);
            }
        }
    }
    
    
}
